use std::{borrow::Cow, fmt, result};

use serde::{
  de::{self, Visitor},
  Deserialize,
};
use tools::ResultEx;

use crate::{config::business_config, db::persistence::InboundDBO};

use super::ISP;

#[derive(Debug, Deserialize)]
pub struct OneCalledRule {
  pub isp: ISP,
  pub rule: CalledRule,
}

#[derive(Debug)]
pub enum CalledRule {
  NoChange,
  AddZero,
  AddAreaCode,
}

impl From<u8> for CalledRule {
  fn from(value: u8) -> Self {
    match value {
      0 => CalledRule::NoChange,
      1 => CalledRule::AddZero,
      2 => CalledRule::AddAreaCode,
      _ => CalledRule::NoChange,
    }
  }
}

impl From<&str> for CalledRule {
  fn from(value: &str) -> Self {
    match value {
      "不改变" => CalledRule::NoChange,
      "前加0" => CalledRule::AddZero,
      "加区号" => CalledRule::AddAreaCode,
      _ => CalledRule::NoChange,
    }
  }
}

impl<'de> serde::Deserialize<'de> for CalledRule {
  fn deserialize<D>(deserializer: D) -> std::prelude::v1::Result<Self, D::Error>
  where
    D: serde::Deserializer<'de>,
  {
    struct CalledRuleVisitor;
    impl<'de> Visitor<'de> for CalledRuleVisitor {
      type Value = CalledRule;

      fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        formatter.write_str("错误")
      }

      fn visit_str<E>(self, value: &str) -> result::Result<CalledRule, E>
      where
        E: de::Error,
      {
        Ok(value.into())
      }
    }

    deserializer.deserialize_str(CalledRuleVisitor)
  }
}

pub async fn handle_called_rule(called: &str) -> ResultEx<Cow<str>> {
  //如果未找到对应的数据。直接进行返回操作
  let Some((isp, area)) = InboundDBO::get_num_isp_info(called).await? else {
    return Ok(Cow::Borrowed(called));
  };

  for rule in business_config().called_rules.iter() {
    if rule.isp == isp {
      match rule.rule {
        CalledRule::NoChange => return Ok(Cow::Borrowed(called)),
        CalledRule::AddZero => {
          return Ok(Cow::Owned(format!("0{}", called)));
        }
        CalledRule::AddAreaCode => {
          return Ok(Cow::Owned(format!("{}{}", area, called)));
        }
      }
    }
  }

  Ok(Cow::Borrowed(called))
}
